import { Vue, Component, Prop, Watch } from 'vue-property-decorator';
import { edger } from '@edgeros/web-sdk';
import style from '@/styles/device.module.less';
import { DropdownMenu, DropdownItem, Field, Button, Popup, RadioGroup, Radio, NumberKeyboard, Switch } from 'vant';
import { ISimpleDevice } from '@/interfaces/device.interface';
import decreaseSvg from '@/assets/decrease.svg';
import { IDeviceCategory, IResponse } from '@/interfaces/common.interface';

interface IOption {
  text: string;
  value: string;
}

type INewItemType = 'string' | 'number' | 'boolean' | 'array';
type IValueType = number | string | boolean | IValueType[];

interface IClientObjectMessage {
  key: string;
  value: IValueType;
}

@Component({
  components: {
    'van-dropdown-menu': DropdownMenu,
    'van-dropdown-item': DropdownItem,
    'van-field': Field,
    'van-button': Button,
    'van-popup': Popup,
    'van-radio-group': RadioGroup,
    'van-radio': Radio,
    'van-number-keyboard': NumberKeyboard,
    'van-switch': Switch
  },
  sockets: {
    connect() {
      // 获取最新的设备列表
        this.$socket.client.emit('list', 'device', (res: IResponse) => {
          if (res && res.result) {
            this.$data.devList = res.data;
          }
        });
    },
    list(data: { type: IDeviceCategory; data: ISimpleDevice[] }) {
      if (data.type === 'device') {
        this.$data.devList = data.data || [];
      }
    },
    message(data: { type: IDeviceCategory; devid: string; data: any }) {
      console.log('[message]:', data);
      if (data.type === 'device' && this.$data.devId === data.devid) {
        this.$data.serverMessage = { ...this.$data.serverMessage, ...data.data };
      }
    }
    // error(data) {
    //   edger.notify.error(data);
    // }
  }
})
export default class Device extends Vue {
  private devId = '';
  private options: IOption[] = [];
  private devList: ISimpleDevice[] = [];
  private clientMessageType: 'object' | 'array' = 'object';
  private clientBufferMessage: IClientObjectMessage[] | IValueType[] = [];
  private clientMessage: { [prop: string]: IValueType } | IValueType[] = {};
  private serverMessage: any = {};
  private showPopup = false;
  private showArrayPopup = false;
  private newItemType: INewItemType = 'string';
  private popupData: IClientObjectMessage = { key: '', value: [] } as IClientObjectMessage;
  private complexBufferText = '';

  @Watch('devList.length')
  public watchDevList() {
    const res = this.devList.map((item: ISimpleDevice) => {
      return {
        text: item.alias,
        value: item.devid
      };
    });
    this.$set(this.$data, 'options', res);
    if (this.devId) {
      const res = this.options.findIndex((item: IOption) => {
        return item.value === this.devId;
      });
      if (res < 0) {
        edger.notify.error('Device lost！');
        this.devId = '';
        this.clientBufferMessage = [];
      }
    }
  }

  @Watch('clientBufferMessage', { immediate: true, deep: true })
  public watchClientBufferMessage(v: IClientObjectMessage[] | IValueType[]) {
    if (this.clientMessageType === 'array') {
      return (this.clientMessage = v as IValueType[]);
    }
    this.clientMessage = this.generateClientMessage(v as IClientObjectMessage[]);
  }

  public created() {
    this.$socket &&
      this.$socket.client.emit('list', 'device', (res: IResponse) => {
        if (res && res.result) {
          this.devList = res.data;
        }
      });
  }

  public mounted() {
    const devDom: HTMLElement | null = document.getElementById('cMsg');
    if (!devDom) {
      return;
    }
    devDom.addEventListener('click', () => {
      if (!this.devId) {
        edger.notify.warning('请先选择通信设备！');
      }
    });
  }

  public render() {
    return (
      <div class={style['device-message']}>
        <p class={style['device-message-title']}>【通信设备】：</p>
        <van-dropdown-menu class={style['device-message-dropdown']} active-color='#20a5de'>
          <van-dropdown-item v-model={this.devId} options={this.options} on-change={this.requestDevice} />
        </van-dropdown-menu>
        <div id='cMsg'>
          <p class={style['device-message-title']}>
            【发送数据】：
            <van-radio-group
              v-model={this.clientMessageType}
              direction='horizontal'
              disabled={!this.devId}
              on-change={this.changeClientMessageType}>
              <van-radio name='object'>Object</van-radio>
              <van-radio name='array'>Array</van-radio>
            </van-radio-group>
          </p>

          {this.renderSendMessage()}
          <van-button
            size='small'
            plain
            color='#20a5de'
            hairline
            icon='plus'
            style={{ marginBottom: '4px' }}
            on-click={this.beforeAddNewItem}
            disabled={!this.devId}>
            新增属性
          </van-button>
          {this.renderPopup()}
          {this.renderArrayPopup()}
          {this.renderComplexMessage()}
          {this.previewClientMessage()}
          <div class={style['device-message-btn']}>
            <van-button  size='small' plain hairline color='#20a5de' disabled={!this.devId} on-click={this.sendMessage}>
              Send
            </van-button>
          </div>
        </div>

        <p class={style['device-message-title']}>【响应数据】：</p>
        <p style={{ padding: '0 8px', 'font-size': '12px' }}>注意：如果设备存在主动上报数据，则也会在此显示</p>
        <div class={style['device-message-response']}>
          <pre>{JSON.stringify(this.serverMessage, null, 2)}</pre>
        </div>
      </div>
    );
  }

  private renderSendMessage() {
    if (this.clientMessageType === 'array') {
      return (
        <div>
          {(this.clientBufferMessage as IValueType[]).map((item: IValueType, idx: number) => {
            return this.renderArrayItem(this.clientBufferMessage as IValueType[], idx);
          })}
        </div>
      );
    } else {
      // object
      return (
        <div>
          {(this.clientBufferMessage as IClientObjectMessage[]).map((item: IClientObjectMessage, idx: number) => {
            return this.renderObjectItem(item, idx);
          })}
        </div>
      );
    }
  }

  private renderObjectItem(item: IClientObjectMessage, idx: number) {
    const valueType = typeof item.value;
    return (
      <div class={style['device-message-input-item']}>
        <van-field v-model={item.key} placeholder='key' style={{ flex: 1 }} />
        {valueType === 'string' && <van-field v-model={item.value} placeholder='value' style={{ flex: 1 }} />}
        {valueType === 'number' && (
          <van-field
            v-model={item.value}
            placeholder='value'
            style={{ flex: 1 }}
            type='number'
            formatter={this.formatNumberInput}
          />
        )}
        {valueType === 'boolean' && (
          <div style={{ flex: 1, background: '#fff', display: 'flex', 'align-items': 'center' }}>
            <van-switch v-model={item.value} active-color='#20a5de' inactive-color='#dcdee0' />
          </div>
        )}
        {Array.isArray(item.value) && (
          <div class={style['device-message-item-array']} on-click={() => this.handleObjectArray(item)}>
            {JSON.stringify(item.value)}
          </div>
        )}
        <img
          src={decreaseSvg}
          alt='decrease'
          on-click={() => {
            this.removeItem(idx);
          }}
        />
      </div>
    );
  }

  private renderArrayItem(arr: IValueType[], idx: number) {
    const valueType = typeof arr[idx];
    return (
      <div class={style['device-message-input-item']}>
        {valueType === 'string' && <van-field v-model={arr[idx]} placeholder='value' style={{ flex: 1 }} />}
        {valueType === 'number' && (
          <van-field
            v-model={arr[idx]}
            placeholder='value'
            style={{ flex: 1 }}
            // type='number'
            formatter={this.formatNumberInput}
          />
        )}
        {valueType === 'boolean' && (
          <div
            style={{ flex: 1, 'padding-left': '12px', background: '#fff', display: 'flex', 'align-items': 'center' }}>
            <van-switch v-model={arr[idx]} active-color='#20a5de' inactive-color='#dcdee0' />
          </div>
        )}
        <img
          src={decreaseSvg}
          alt='decrease'
          on-click={() => {
            this.removeItem(idx);
          }}
        />
      </div>
    );
  }

  private renderComplexMessage() {
    return (
      <div class={style['device-message-complex']}>
        <div>复杂数据拷贝至此：</div>
        <van-field
          rows='2'
          v-model={this.complexBufferText}
          autosize
          type='textarea'
          on-input={this.changeClientMessageByComplex}
          disabled={!this.devId}
          placeholder='仅支持JSON格式数据'
          show-word-limit
        />
      </div>
    );
  }

  private previewClientMessage() {
    return (
      <div class={style['device-message-response']}>
        <div style={{ margin: '8px', color: '#20a5de' }}>发送数据预览：</div>
        <pre>{JSON.stringify(this.clientMessage, null, 2)}</pre>
      </div>
    );
  }

  private renderPopup() {
    return (
      <van-popup v-model={this.showPopup} position='bottom'>
        <div class={style['device-message-popup']}>
          <div>选择插入{this.clientMessageType === 'array' ? '数组选项' : '对象属性值value'}的类型：</div>
          <van-radio-group class={style['device-message-popup-content']} v-model={this.newItemType}>
            <van-radio name='string'>String</van-radio>
            <van-radio name='boolean'>Boolean</van-radio>
            <van-radio name='number'>Number</van-radio>
            {this.clientMessageType === 'object' && <van-radio name='array'>Array</van-radio>}
          </van-radio-group>
          <div class={style['device-message-popup-btn']}>
            <van-button color='#20a5de' size='small' on-click={this.addNewItem}>
              创建
            </van-button>
          </div>
        </div>
      </van-popup>
    );
  }

  private renderArrayPopup() {
    return (
      <van-popup v-model={this.showArrayPopup}>
        <div class={style['device-message-array-popup']}>
          <div>输入数组项（选项用英文;隔开）</div>
          <div>目前仅支持字符串：</div>
          <van-field
            autosize
            rows='3'
            type='textarea'
            value={(this.popupData.value as IValueType[]).join(';')}
            placeholder='abc;xxx;sss'
            on-input={this.arrayPopupInputChange}
          />
        </div>
      </van-popup>
    );
  }

  private async sendMessage() {
    const res = this.checkClientMessage();
    if (!res) return;
    let len = 0;
    if (this.clientMessageType === 'array') {
      len = (this.clientMessage as IValueType[]).length;
    } else {
      len = Object.keys(this.clientMessage).length;
    }
    if (!len) {
      return edger.notify.error('发送数据不可为空！');
    }
    this.$socket.client.emit(
      'send-message',
      { type: 'device', data: { devid: this.devId, data: this.clientMessage } },
      (res: IResponse) => {
        if (!res || !res.result) {
          return this.$edger.notify.error(res.message || '消息发送失败！');
        }
      }
    );
  }

  private changeClientMessageByComplex(v: string) {
    this.clientMessage = this.clientMessageType === 'array' ? [] : {};
    let data: any;
    try {
      data = JSON.parse(v);
    } catch (error) {
      return edger.notify.error('数据格式错误！');
    }
    this.clientBufferMessage = [];
    this.$nextTick(() => {
      this.clientMessage = data;
      this.clientMessageType = Array.isArray(data) ? 'array' : 'object';
    });
    // console.log(111,this.clientBufferMessage, this.clientMessageType, this.clientMessage)
  }

  private async requestDevice() {
    this.clientBufferMessage = [];
    this.serverMessage = {};
    this.complexBufferText = '';
    this.$socket.client.emit('request-control-device', { type: 'device', devid: this.devId }, (res: IResponse) => {
      if (!res || !res.result) {
        this.$edger.notify.error(res.message || '当前应用没有权限控制该设备！');
        this.devId = '';
      } else {
        this.$edger.notify.success('设备切换成功！');
      }
    });
  }

  private checkClientMessage() {
    if (this.clientMessageType === 'object') {
      const idx = Object.keys(this.clientMessage).findIndex((item: string) => {
        return item.trim() === '';
      });
      if (idx > -1) {
        edger.notify.error('数据对象属性名不可为空！');
        return false;
      }
    }
    return true;
  }

  private beforeAddNewItem() {
    const res = this.checkClientMessage();
    if (res) {
      this.showPopup = true;
    }
  }

  private addNewItem() {
    this.showPopup = false;
    let newValue: IValueType = '';
    switch (this.newItemType) {
      case 'string':
        newValue = '';
        break;
      case 'number':
        newValue = 1;
        break;
      case 'boolean':
        newValue = false;
        break;
      case 'array':
        newValue = [];
        break;
      default:
        edger.notify.error('添加数据类型未知！');
        break;
    }
    if (this.clientMessageType === 'object') {
      (this.clientBufferMessage as IClientObjectMessage[]).push({ key: '', value: newValue });
    } else {
      // array
      (this.clientBufferMessage as IValueType[]).push(newValue);
    }
    if (this.complexBufferText) {
      this.complexBufferText = '';
    }
  }

  private changeClientMessageType() {
    this.clientBufferMessage = [];
    this.complexBufferText = '';
  }

  private generateClientMessage(v: IClientObjectMessage[]) {
    return v.reduce((res: any, item: IClientObjectMessage) => {
      res[item.key] = item.value;
      return res;
    }, {} as any);
  }

  private formatNumberInput(v: any) {
    if (v === undefined) {
      return 0;
    }
    if (!/^[-]?[1-9][0-9]*.?[0-9]*$/.test(v)) {
      return parseFloat(v.substr(0, v.length - 1));
    }
    return parseFloat(v);
  }

  private removeItem(index: number) {
    this.clientBufferMessage.splice(index, 1);
  }

  private handleObjectArray(item: IClientObjectMessage) {
    this.popupData = item;
    this.showArrayPopup = true;
  }

  private arrayPopupInputChange(v: string) {
    this.popupData.value = v.split(';');
    this.clientBufferMessage = (this.clientBufferMessage as IClientObjectMessage[]).map(
      (item: IClientObjectMessage) => {
        if (item.key === this.popupData.key) {
          item.value = this.popupData.value;
        }
        return item;
      }
    );
  }
}
